﻿using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Plasp.WebScoketServer.Web.WebSocketProvider
{
    public class ConnectionManager
    {
        /// <summary>
        /// socket连接对象
        /// </summary>
        private static ConcurrentDictionary<string, WebSocket> _webSocketConns =
            new ConcurrentDictionary<string, WebSocket>();

        /// <summary>
        /// 获取实例
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public WebSocket GetWebSocketByKey(string key)
        {
            return _webSocketConns.ContainsKey(key) ? _webSocketConns[key] : null;
        }

        /// <summary>
        /// 获取所有连接
        /// </summary>
        /// <returns></returns>
        internal ConcurrentDictionary<string, WebSocket> GetAllConnctions()
        {
            return _webSocketConns;
        }

        /// <summary>
        /// 获取Key
        /// </summary>
        /// <param name="socket"></param>
        /// <returns></returns>
        public string GetKey(WebSocket socket)
        {
            return _webSocketConns.FirstOrDefault(t => t.Value == socket).Key;
        }

        /// <summary>
        /// 移除一个连接
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public async Task RemoveSocketAsync(string key) {
            _webSocketConns.TryRemove(key, out var socket);
            if (socket != null)
                await socket.CloseAsync(WebSocketCloseStatus.NormalClosure, "socket connection closed",
                    CancellationToken.None);
        }

        /// <summary>
        /// 移除断开连接的实例
        /// </summary>
        /// <returns></returns>
        public async Task RemoveUnConnected() {
            var lst = GetAllConnctions();
            foreach (var skt in lst) {
                if (skt.Value.State != WebSocketState.Open)
                    await RemoveSocketAsync(skt.Key);
            }
        }

        /// <summary>
        /// 添加一个连接
        /// </summary>
        /// <param name="socket"></param>
        public void AddWebSocket(WebSocket socket)
        {
            _webSocketConns.TryAdd(GetConnectionKey(), socket);
        }

        /// <summary>
        /// 获取一个Key
        /// <para>the key form Guid</para>
        /// </summary>
        /// <returns></returns>
        protected string GetConnectionKey()
        {
            return Guid.NewGuid().ToString("N");
        }

        /// <summary>
        /// 向客户端发送数据
        /// </summary>
        /// <param name="message">数据</param>
        /// <param name="webSocket">socket对象  sleep 心跳周期</param>
        /// <returns></returns>
        public async Task SendAsync(string message, WebSocket webSocket)
        {
            try
            {
                //业务逻辑
                var cancellation = default(CancellationToken);
                var buf = Encoding.UTF8.GetBytes(message);
                var segment = new ArraySegment<byte>(buf);
                await webSocket.SendAsync(segment, WebSocketMessageType.Text, true, cancellation);
            }
            catch (Exception)
            {
                //TODO  要做日志记录
                await RemoveSocketAsync(GetKey(webSocket));
            }
        }
    }
}
